<template>
  <el-dialog :close-on-click-modal="true" :title="titleText" :visible.sync="visible" custom-class="dialog_big"
    @close="rows.forEach(it => it.visible = false)" v-bind="$attrs" v-on="$listeners">
    <el-image v-if="previewImageObj && previewImageObj.url" ref="previewImage" :src="previewImageObj.url"
      :preview-src-list="previewImageList" style="display: none;" @error="previewImageError">
    </el-image>
    <div class="flex_col_center">
      <ex_super_form ref="form" :model="formModel" :data="printOption" :rules="useRules"
        :label-width="$globalCss.formLabelWidth_default" inputClass="w_fill" class="w_fill"
        :validate-on-rule-change="false">
        <template v-slot:form_before="">
          <el-form-item :label="$tt('label_print_client')" prop="clientId" v-if="ableClientPrint">
            <common_select_print_client class="flex_cell w_fill" :printClientParam="printClientParam"
              :printClientUrl="printClientUrl" :clientId.sync="printOption.clientId"
              :printerName.sync="printOption.printerName" />
          </el-form-item>
          <el-form-item :label="$tt('label_print_template')" prop="templateId" v-if="templateNeed"
            :required="templateRequire" :rules="ruleTemplate">
            <div class="flex_row">
              <common_select_print_template class="flex_cell" v-model="printOption.templateId"
                :businessType="businessType" />
              <el-button v-if="generateUrl" class="mg_l1" sizi="small" @click="clickPreview(null, null)">
                {{ $tt('label_preview') }}</el-button>
            </div>
          </el-form-item>
          <el-form-item :label="$tt('label_generate_mark_count')" prop="generateNumber" v-if="generateUrl">
            <el-input-number class="flex_cell w_fill" v-model="generateNumber" :min="1" :max="99" step-strictly />
          </el-form-item>
          <el-form-item :label="$tt('label_single_mark_copies_count')" prop="printNumSum"
            v-if="!setDefaultOptionMode && !generateUrl && ableClientPrint">
            <el-input-number class="flex_cell w_fill" v-model="printOption.printNumSum" :min="1" :max="99" step-strictly
              @input="printNumSumInput" />
          </el-form-item>
        </template>
      </ex_super_form>

      <ex_super_table ref="table" :model="buildTableModel" :data="rows" height="300" class="w_fill" v-if="tableNeed"
        @selection-change="e => selection = e">
      </ex_super_table>
    </div>

    <span slot="footer" class="dialog_footer">
      <el-button @click="visible = false">{{ $tt('label_cancel') }}</el-button>
      <el-button type="primary" @click="clickDefaultOption" v-if="setDefaultOptionMode">
        {{ $tt('label_auto_print_option') }}
      </el-button>
      <template v-else>
        <el-button @click="printBatchMergeDownload" v-if="!!previewMergeUrl && tableNeed" :loading="loading"
          :disabled="loading">
          {{ $t('label_batch_merge_download') }}({{ operateCount }})
        </el-button>
        <el-button @click="printBatchDownload" v-if="tableNeed" :loading="loading" :disabled="loading">
          {{ $t('label_batch_zip_download') }}({{ operateCount }})
        </el-button>
        <template v-if="singlePrint">
          <el-button type="primary" @click="downloadBeforeCheck">{{ $tt('label_download') }}</el-button>
          <el-button type="primary" @click="printBrowserBeforeCheck">{{ $tt('label_browser_print') }}</el-button>
        </template>
        <el-button type="primary" v-if="ableClientPrint" @click="printClientBeforeCheck" :loading="loading"
          :disabled="loading">
          {{ $t('label_client_print') }} {{ tableNeed ? `(${operateCount})` : '' }}
        </el-button>

      </template>

    </span>
  </el-dialog>
</template>

<script>
import JSzip from 'jszip'
import FileSaver from 'file-saver'
import common_select_print_client from './common_select_print_client.vue'
import common_select_print_template from './common_select_print_template.vue'
import business_function from "@/common/business_function";
import role_system_mixin from '@/mixin/role_system_mixin';

const default_obj = {
  printNumSum: 1,
  templateId: "",
  clientId: "",
  printerName: "",
}
export default {
  mixins: [role_system_mixin,],
  components: { common_select_print_client, common_select_print_template, },
  data() {
    return {
      titleText: null,
      setDefaultOptionMode: this.setDefaultOptionModeOpen,

      printOption: this.getDefaultData(),
      generateNumber: 1,
      generateParams: {},
      generateTemps: [],
      visible: false,
      loading: false,
      previewImageObj: null,
      option: [],
      rows: [],
      selection: [],
      buildTableModel: [],
      rules: {
        clientId: {
          required: true, label: "label_print_client",
          validator: (r, v, cb) => {
            if (_.isEmpty(this.printOption.clientId)) {
              return cb(this.$tt("tip_can_no_empty"))
            }
            cb()
          },
        },
        generateNumber: {
          required: true, label: "label_generate_mark_count",
          validator: (r, v, cb) => {
            if (!this.$reg.PureNumber(this.generateNumber)) {
              return cb(this.$tt("tip_only_positive_pure_decimal"))
            }
            cb()
          },
          trigger: 'blur'
        },
        printNumSum: {
          required: true, label: "label_single_mark_copies_count",
          validator: (r, v, cb) => {
            if (!this.$reg.PureNumber(this.printOption.printNumSum)) {
              return cb(this.$tt("tip_only_positive_pure_decimal"))
            }
            cb()
          },
          trigger: 'blur'
        },

      },
    }
  },
  props: {
    title: {
      type: String,
      default: "",
    },
    //打印模板业务类型
    businessType: {
      type: String,
      default: "",
    },
    //额外业务类型
    extraBusinessType: {
      type: String,
      default: null,
    },
    printUrl: String,
    printHandler: Function,
    previewUrl: String,
    previewHandler: Function,

    previewMergeUrl: String,
    previewMergeHandler: null,
    //生成codeUrl
    generateUrl: String,
    //本地存储key
    localStorageKey: {
      type: String,
      default: null,
    },


    //是否默认设置打印配置模式
    setDefaultOptionModeOpen: {
      type: Boolean,
      default: false,
    },
    singlePrint: {
      type: Boolean,
      default: false,
    },
    //是否可以为单个条目设置打印数量
    singlePrintNumber: {
      type: Boolean,
      default: false,
    },
    //是否需要模板
    templateVisiable: {
      type: Boolean,
      default: true,
    },
    //是否模板必填
    templateRequire: {
      type: Boolean,
      default: true,
    },
    tableVisiable: {
      type: Boolean,
      default: true,
    },
    //表格配置Model
    tableModel: {
      type: Array,
      default: () => []
    },

    //表单配置Model
    formModel: {
      type: Array,
      default: () => []
    },
    formRules: {
      type: Object,
      default: () => { }
    },
    //表单配置Default
    formDefualt: {
      type: Object,
      default: () => { }
    },
    //配置获取连接url方法
    urlGetFun: null,
    printClientUrl: String,
    printClientParam: {
      type: Object,
      default: () => { },
    },
  },
  mounted() {


    // this.$emit("sureDefaultOption", printData)
    this.buildTableModel = this.buildTableModelGet()
  },
  watch: {
    'tableModel'(val, old) {
      this.buildTableModel = this.buildTableModelGet()
    }
  },
  computed: {
    useRules() {
      return Object.assign({}, this.rules, this.formRules, {
        templateId: this.ruleTemplate,
      })
    },
    ableClientPrint() {
      return this.isWmsSystem || this.isCustomerSystem
    },
    templateNeed() {
      return this.templateVisiable && this.businessType
    },
    tableNeed() {
      return !this.setDefaultOptionMode && !this.generateUrl && this.tableVisiable
    },
    operateCount() {
      return this.generateUrl ? this.generateNumber : this.selection.length
    },
    previewImageList() {
      if (this.generateUrl) {
        return this.previewImageObj ? [this.previewImageObj.url] : []
      }
      return this.rows.map(row => this.createPreviewLink('png', row).url)
    },
    ruleTemplate() {
      return {
        trigger: 'blur',
        require: this.templateRequire,
        label: "label_print_template",
        validator: (r, v, cb) => {
          if ((!this.printOption.templateId) && this.templateRequire) {
            return cb(this.$tt("tip_can_no_empty"))
          }
          cb()
        },
      }
    },


  },
  methods: {
    getDefaultData() {
      return _.cloneDeep(Object.assign({}, default_obj, this.formDefualt))
    },
    // removeDefaultOption() {
    //   window.localStorage.removeItem(this.userLocalStorageKey)
    //   this.$emit("sureDefaultOption", null)
    // },
    buildTableModelGet() {
      return [
        {
          type: 'selection', clickToggle: true, keyGroup: 'label_table_operate',
          clickExclude: ['print_copies_count', 'operate_area'],
        },
        ...this.tableModel,
        {
          key: 'print_copies_count',
          label: 'label_print_copies_count', width: 140, if: () => this.singlePrintNumber,
          render: (h, { row }) => {
            return (<el-input-number value={row.printNum} onInput={e => this.$set(row, 'printNum', e)}
              min={0} max={999999}
              step-strictly class="w_fill" />)
          }
        },
        {
          type: 'operate', width: 300, operate: [
            {
              label: "label_preview", attrs: { type: "", size: "small" },
              if: () => this.templateNeed,
              click: (row) => this.clickPreview(null, row)
            },
            {
              label: "label_download", attrs: { type: "", size: "small" },
              click: (row) => this.downloadPdf(null, row)
            },
            {
              label: "label_browser_print", attrs: { type: "", size: "small" },
              click: (row) => this.printBrowser(null, row)
            },
          ],
        },
      ]
    },
    buildUrl(row) {
      const urlObj = this.urlGetFun(row)
      if (!urlObj) return null
      if (urlObj.intact) {
        return urlObj.url
      } else if (urlObj.oss) {
        return this.$ex_default_download_url + urlObj.url
      } else {
        return urlObj.url
      }
    },

    createPreviewLink(fileType, row) {
      if (this.urlGetFun) {
        const url = this.buildUrl(row)
        if (url) return {
          base: url,
          url,
          fileType: this.$reg.FileExt(url),
          params: {},
        }
      }
      const params = this.createPreviewLinkData(fileType, row)
      const previewLink = this.previewUrl + `?` +
        this.$qs.stringify(params)
      return {
        base: this.previewUrl,
        url: previewLink,
        fileType,
        params,
      }
    },

    createPreviewMergeLink(fileType, rows) {
      const previewLink = this.previewMergeUrl + `?` +
        this.$qs.stringify(this.createPreviewMergeLinkData(fileType, rows))
      return previewLink
    },
    createPreviewMergeLinkData(fileType, rows) {
      let data = {
        type: this.businessType, templateId: this.printOption.templateId,// clientName: this.clientId, printerName: this.printerName, printNumSum: this.printNumSum,
        fileType: fileType
      }
      if (this.$refs.form) Object.assign(data, this.$refs.form.getFormData())
      return this.previewMergeHandler(data, rows)
    },
    createPreviewLinkData(fileType, row) {
      let data = {
        type: this.businessType, templateId: this.printOption.templateId,// clientName: this.clientId, printerName: this.printerName, printNumSum: this.printNumSum,
        fileType: fileType
      }
      if (this.$refs.form) Object.assign(data, this.$refs.form.getFormData())
      return this.previewHandler(data, row)
    },
    //单个条目下载
    downloadPdf(e, row) {

      if (this.$clickFast()) return
      if ((!this.printOption.templateId) && this.templateNeed && this.templateRequire) return this.$message.error(this.$tt('label_please_select_print_template'))
      this.$downloadFile({
        a: true, target: '_blank',
        url: this.createPreviewLink('pdf', row).url
      })
      this.setDefaultOption(this.printOption)
    },
    //合并pdf下载
    //浏览器打印
    printBrowser(e, row) {
      if (this.$clickFast()) return
      if ((!this.printOption.templateId) && this.templateNeed && this.templateRequire) return this.$message.error(this.$tt('label_please_select_print_template'))
      const previewObj = this.createPreviewLink('pdf', row)

      printJS({
        printable: previewObj.url,
        type: previewObj.fileType === "pdf" ? previewObj.fileType : "image",
        showModal: true
      })
      this.setDefaultOption(this.printOption)

    },
    printBatchMergeDownload() {
      if (this.$clickFast()) return
      if ((!this.printOption.templateId) && this.templateNeed && this.templateRequire) return this.$message.error(this.$tt('label_please_select_print_template'))
      this.$downloadFile({
        // a: true, target: '_blank',
        type: "json", loading: true,
        url: this.previewMergeUrl,
        data: this.createPreviewMergeLinkData('pdf', this.selection)
      })
      this.setDefaultOption(this.printOption)
    },
    //合并zip下载

    printBatchDownload() {
      if (this.$clickFast()) return
      if ((!this.printOption.templateId) && this.templateNeed && this.templateRequire) return this.$message.error(this.$tt('label_please_select_print_template'))

      let loading = this.$loading({
        lock: true,
        text: this.$tt('tip_downloading'),
      });
      this.generateBuild((list) => {
        Promise.all(
          list.map((row, i) =>
            new Promise((resolve, reject) => {
              const previewObj = this.createPreviewLink('pdf', row)
              this.$downloadFile({
                url: previewObj.url,
                download: false,
                success: (blob, fileName) => {
                  resolve({ blob, fileName })
                },
                fail: (result, err) => {
                  reject({ result, err })
                },
              })
            })
          )
        ).then(results => {
          loading.close();
          loading = this.$loading({ lock: true, text: this.$tt('tip_ziping'), });
          const zip = new JSzip()
          const zipPromise = results.map(({ fileName, blob }) => zip.file(fileName, blob))
          Promise.all(zipPromise)
            .then(zipinto => {
              zip.generateAsync({ // 生成二进制流
                type: 'blob'
              }).then(content => {
                loading.close();
                FileSaver.saveAs(content, `${this.$t("label_batch_download")}-${this.$enumShow(this.businessType, 'PrintBussinessTypeEnum')}.zip`)
                this.setDefaultOption(this.printOption)
              }).catch(e => {
                loading.close();
              })
            }).catch(e => {
              loading.close();
            })


        }).catch(e => {
          this.$message.error(this.$tt('label_download_fail'))
          loading.close();
        })
      }, this.generateNumber)

    },

    //客户端打印

    print(list) {
      let data = {
        type: this.businessType, templateId: this.printOption.templateId, clientName: this.printOption.clientId, printerName: this.printOption.printerName,
        printNumSum: this.printOption.printNumSum, fileType: 'pdf', clientId: this.printOption.clientId
      }
      if (this.$refs.form) Object.assign(data, this.$refs.form.getFormData())
      this.loading = true
      this.$ajax({
        url: this.printUrl,
        method: 'post', type: 'json',
        loading: true,
        data: this.printHandler(data, list),
        success: (res) => {
          this.$message.success(this.$tt('label_submit_print_success'))

          this.visible = false
          this.setDefaultOption(this.printOption)
        },
        complete: () => {
          this.loading = false
        }
      })
    },
    clickDefaultOption() {
      if (this.$clickFast()) return
      this.$refs['form'].validate((valid) => {
        if (valid) {
          this.$emit("sureDefaultOption", this.printOption)
          this.visible = false
        } else {
          this.$message.error(this.$tt('form_validate_error'))
          return false;
        }
      });
    },
    getCachePrintConfig(businessType) {
      const localPrintConfig = business_function.loadPrintConfig({
        typeKey: businessType ? businessType : (this.extraBusinessType ? this.extraBusinessType : this.businessType),
        storageKey: this.localStorageKey
      })
      if (_.isEmpty(localPrintConfig)) return null
      return Object.assign(this.getDefaultData(), _.head(localPrintConfig))
    },

    restoreDefaultOption() {

      if (this.businessType || this.extraBusinessType || this.localStorageKey) {
        this.printOption = this.getCachePrintConfig()
        return this.printOption
      } else {
        return null
      }

    },
    //设置默认打印配置打印
    setDefaultOption(data) {
      this.printOption = Object.assign(this.getDefaultData(), data)
      business_function.savePrintConfig({
        data: this.printOption,
        storageKey: this.localStorageKey,
      })
    },
    //获取默认打印配置打印

    printDefaultOption({ list, businessType, extraBusinessType, url, handler, templateRequire }) {
      const proprintType = extraBusinessType ? extraBusinessType : this.extraBusinessType
      const printType = businessType ? businessType : this.businessType

      let localPrintConfig = null
      if (proprintType) {
        localPrintConfig = this.getCachePrintConfig(proprintType)
      }
      if (!localPrintConfig) {
        localPrintConfig = this.getCachePrintConfig(printType)
      }
      if (!localPrintConfig) {
        this.$nextTick(() => {
          this.$message.error(this.$tt('无打印配置'))
        })
        return
      }
      let data = {
        type: localPrintConfig.linkKey ? localPrintConfig.linkKey : localPrintConfig.key, templateId: localPrintConfig.templateId, clientName: localPrintConfig.clientId, printerName: localPrintConfig.printerName,
        printNumSum: localPrintConfig.printNumSum, fileType: 'pdf', clientId: localPrintConfig.clientId
      }

      let checkTemplate = false
      if (_.isBoolean(templateRequire)) {
        checkTemplate = templateRequire
      } else {
        checkTemplate = (this.templateNeed && this.templateRequire)
      }
      if (checkTemplate && !data.templateId) {
        this.$nextTick(() => {
          this.$message.error(this.$tt('label_please_select_print_template'))
        })
        return
      }

      this.loading = true
      if (handler) {
        data = handler(data, list)
      } else {
        data = this.printHandler(data, list)
      }
      this.$ajax({
        url: url || this.printUrl,
        method: 'post',
        type: 'json',
        loading: true,
        data,
        success: (res) => {
          this.$message.success(this.$tt('label_submit_print_success'))
        },
        complete: () => {
          this.loading = false
        }
      })
    },
    downloadBeforeCheck() {
      if (this.$clickFast("check")) return

      this.$formRulesValidate({
        formRef: this.$refs['form'],
        rules: this.useRules,
        props: _.concat(Object.keys(this.useRules).filter(it => it != "clientId"), this.templateNeed ? 'templateId' : []),
        success: () => {
          this.downloadPdf(null, {})
        }
      })
    },
    printBrowserBeforeCheck() {
      if (this.$clickFast("check")) return

      this.$formRulesValidate({
        formRef: this.$refs['form'],
        rules: this.useRules,
        props: _.concat(Object.keys(this.useRules).filter(it => it != "clientId"), this.templateNeed ? 'templateId' : []),
        success: () => {
          this.printBrowser(null, {})
        }
      })
    },
    //获取客户端打印前检查

    printClientBeforeCheck() {
      if (this.$clickFast()) return
      this.$formRulesValidate({
        formRef: this.$refs['form'],
        rules: this.useRules,
        success: () => {
          this.generateBuild((list) => {
            this.print(list)
          }, this.generateNumber)
        }
      })
    },
    //获取预览
    clickPreview(e, row) {
      if ((!this.printOption.templateId) && (this.templateNeed && this.templateRequire)) return this.$message.error(this.$tt('label_please_select_print_template'))
      this.generateBuild((list, ok) => {
        this.previewImageObj = this.createPreviewLink('png', ok ? _.head(list) : row)
        this.$nextTick(() => {
          this.$refs.previewImage.showViewer = true
        })
      }, 1)
    },
    //预览错误
    previewImageError(e) {
      this.$ajax({
        url: this.previewImageObj.base,
        type: "form",
        data: this.previewImageObj.params,
        fail: (res) => {
          this.$message.error(this.$t('tip_photo_load_fail') + "! " + JSON.stringify(res))
          // this.previewImageObj.previewError = JSON.stringify(res)
        },
      })
    },
    generateBuild(call, number) {
      if (!this.generateUrl) {
        call(this.selection, false)
      } else if (this.generateTemps.length >= number) {
        call(this.generateTemps.slice(0, number), true)
      } else {
        this.generate(() => {
          call(this.generateTemps, true)
        }, number - this.generateTemps.length)
      }
    },

    generate(call, number,) {
      this.$ajax({
        url: this.generateUrl,
        method: 'post',
        loading: true,
        data: { number: number, ...this.generateParams },
        success: (res) => {
          if (res && res.data && !_.isEmpty(res.data.rows)) {
            this.generateTemps.push(...res.data.rows)
            call(res.data.rows)
          }
        },
        failure: (res) => {
        },
        complete: () => {
        }
      })
    },
    show(rows, option,) {
      const localPrintConfig = this.restoreDefaultOption()
      this.printOption.printNumSum = 1
      const list = rows ? _.cloneDeep(rows) : []
      list.forEach(it => {
        if (it.printNum == undefined) {
          this.$set(it, 'printNum', this.printOption.printNumSum)
        }
      })
      if (this.ableClientPrint && option && option.single) {
        if (localPrintConfig && localPrintConfig.clientId) {

          let checkTemplate = false
          if (_.isBoolean(option.templateRequire)) {
            checkTemplate = option.templateRequire
          } else {
            checkTemplate = (this.templateNeed && this.templateRequire)
          }
          if (!checkTemplate || localPrintConfig.templateId) {
            this.printDefaultOption({
              list: list,
              ...option
            })
            return
          }
        }
      }

      if (option && option.default) {
        this.printOption = Object.assign({}, this.printOption, option.default)
      }

      if (option && option.title) {
        this.titleText = option.title
      } else if (this.businessType) {
        this.titleText = this.$tt('label_print_any', { type: this.$enumShow(this.businessType, 'PrintBussinessTypeEnum') })
      } else {
        this.titleText = this.title
      }
      this.generateTemps = []

      this.setDefaultOptionMode = option && option.setDefaultOptionMode
      if (option) {
        if (option.generateParams) {
          this.generateParams = option.generateParams
        }
      }
      this.visible = true
      if (!this.setDefaultOptionMode) {
        this.$nextTick(() => {
          // this.$refs.table.setData(list)
          this.rows = list
          if (this.$refs.table) this.$refs.table.toggleAllSelection()
        })
      }

    },

    printNumSumInput(e) {
      this.rows.forEach(it => {
        this.$set(it, 'printNum', e)
      })
    },


  }
}
</script>
